using System;
using System.Collections.Generic;
using Mahjong.Logic;
using Microsoft.FSharp.Collections.Tagged;
using Unity.VisualScripting;

namespace Mahjong.Logic
{
public class Logic
{
    private Manager manager;
    private Data data=new Data();//data只由logic实例化并维护
    private int isOperationProcessed;//是否已经处理玩家操作
    //设置并传出isOperationProcessed
    private GameStatus currentStatus = GameStatus.Preparing;
    private Dictionary<int, List<string>> playerAvailableOperations = new Dictionary<int, List<string>>();

    public enum GameStatus
    {
        Preparing,  // 准备阶段
        Drawing,    // 摸牌阶段
        Discarding, // 出牌阶段
        Responding, // 玩家响应阶段
        Ended       // 游戏结束
    }
    public bool IsOperationProcessed()
    {
        return isOperationProcessed == 1;
    }

    public void SetOperationProcessed(bool processed)
    {
        isOperationProcessed = processed ? 1 : 0;
    }

    //传入manager实例
     public void ResetGameData()
    {
        data.ResetGameData();
    }
     public void CalculateFinalScores()
    {
        data.CalculateFinalScores();
    }

     public void SetManager(Manager manager)
    {//设置manager实例，初始数据对象data
        if (this.manager!= null)
        {
            throw new InvalidOperationException("Manager instance already set.");
        }
        this.manager = manager;
    }
    
   //准备游戏，创建牌堆并洗牌
    public void PrepareGame()
    { 
        List<int> allCards = data.GenerateAllCards();
        ShuffleCards(allCards); 
        // 获取金牌的随机索引
        int goldCardIndex = new Random().Next(allCards.Count);
        int goldCardValue = allCards[goldCardIndex];
        data.SetGoldCard(goldCardValue);
        // 通过索引移除被选中的那张牌,剩下的牌作为后续的发牌堆
        allCards.RemoveAt(goldCardIndex);
        List<int> cardsForDistribute=allCards;
        data.SetCardsForDistribute(cardsForDistribute);//设置新牌堆
    } /*上面这段还没发牌，无需和player交互*/

    //开始发牌
    public void StartDistribute()
    {

        //获取洗牌并去除金牌后的牌堆
        List<int> cardsForDistribute = data.GetCardsForDistribute();
        int playerCount = data.GetPlayerCount(); 
        int initialCards = data.GetCardsForDistribute().Count; 
        //0,1,2,3逆时针顺序依次发牌,0的位置是庄家
        for (int i = 0; i <playerCount; i++)
        {
        int startIndex=i*initialCards;//计算当前玩家的起始索引，当前规则下恒定为0，16,32,48
        //得到当前玩家的初始手牌
        List<int> handCards = cardsForDistribute.GetRange(startIndex, initialCards);//起始目录，长度
        //更新每位玩家的手牌数据
        data.UpdateHandCard(i, handCards);
        // 通过 Manager 调用 Player 的方法更新手牌
        manager.UpdatePlayerHandCards(i, handCards);
        }
        // 预计算剩余数量，确定初始发牌过后，剩下的摸牌起始点的索引
        //例如112张牌，初始发64，摸牌起始点为16*4=64，可摸牌数112-64=48
        int drawCardStartIndex = initialCards * playerCount;
        int drawCardCount = cardsForDistribute.Count - drawCardStartIndex;
        // 获取摸牌区间，GetRange(startIndex, count)从起始目录开始往后摸指定长度
        List<int> drawCard = cardsForDistribute.GetRange(drawCardStartIndex, drawCardCount);
        data.SetDrawCard(drawCard); // 设置摸牌区间
        data.SetDrawIndex(0); // 初始化摸牌索引为0，表示从摸牌区间的起始位置开始摸牌
        }//发牌结束，处理好摸牌牌堆

    //处理玩家操作
    public void ProcessPlayerOperation(int playerId, string operation, int? card)
    {
        isOperationProcessed = 0;
        switch (operation.ToLower())
        {
            case "discard"://弃牌
                if (card.HasValue)//判断牌号是否为空
                {
                    DiscardCard(playerId, card.Value);
                }
                break;
            case "draw"://摸牌
                if (card.HasValue)
                {
                    DrawCard(playerId, card.Value);
                }
                break;
            case "hu"://胡牌
                CheckHu(playerId);
                break;
            case "peng"://碰牌
                if (card.HasValue)
                {
                    PengCard(playerId, card.Value);
                }
                break;
            case "gang"://杠牌
                if (card.HasValue)
                {
                    GangCard(playerId, card.Value);
                }
                break;
            case "chi"://吃牌
                if (card.HasValue)
                {
                    ChiCard(playerId, card.Value);
                }
                break;
            default://错误判断
                Console.WriteLine("未知的操作类型");
                break;
        }
        isOperationProcessed = 1;
    }

    //检查游戏是否结束
    public bool CheckGameEnd()
    {
        if (data.IsGameEndConditionMet())
        {
            data.CalculateFinalScores();//牌打完或者有人胡
            manager.GameEndHandling(data.GetFinalScores(),data.GetWinningPlayer());
            return true;
        }
        else
        {
            ContinueNextTurn();
            return false;
        }
    }

    //继续下一回合
    private void ContinueNextTurn()
    {
        // 切换到下一个玩家的出牌回合
        int nextPlayerId= manager.SwitchTurn();   
        Console.WriteLine($"切换到玩家 {nextPlayerId}的出牌回合");
    }
    //更新玩家信息到data中
    public void UpdatePlayerInformation(int playerId, Dictionary<int, string> playerInfo)
        {
        data.SetPlayerInformation(playerId, playerInfo);
        Console.WriteLine($"Player information updated for player {playerId}.");
        }

    

    //获取玩家数量
    public int GetPlayerCount()
    {
        return data.GetPlayerCount();
    }

    //洗牌
    private void ShuffleCards(List<int> cards)
    {
        Random random = new Random();
        for (int i = cards.Count - 1; i > 0; i--)
        {
            int j = random.Next(i + 1);
            int temp = cards[i];
            cards[i] = cards[j];
            cards[j] = temp;
        }
    }

    //选出“金”牌
    private int SelectGoldCard(List<int> allCards)
    {
        Random random = new Random();
        return allCards[random.Next(allCards.Count)];//在摸牌时都跳过金牌
        /*如果发牌的时候发到了金牌，说明发牌方向错了，重新调试*/
    }

    //弃牌
    //包含了更新牌堆和判断玩家操作
    public void DiscardCard(int playerId, int card)
    {
        data.UpdateDiscard(playerId, card);
        /*调用manager，通知player通知playerUI更新手牌区，将牌举起*/
        manager.UpdatePlayerHandScene(playerId, data.GetHandCards(playerId));
        //判断其他玩家可能的操作 
       List<string> availableOperations = CheckOtherPlayersOperations(playerId, card);
       SetAvailableOperations(playerId, availableOperations);
        /*如果其他玩家没有进行操作了，就更新弃牌至弃牌区*/
        if (availableOperations.Count == 0)
        {
            data.UpdateDiscard(playerId,card);
            //通过manager通知player更新弃牌界面
             manager.UpdatePlayerDiscardScene(playerId, data.GetDiscardCards(playerId));
        }
        /*如果其他玩家有了对应操作，按优先级排序之后返回优先级给manager*/
    }
    public void SetAvailableOperations(int playerId, List<string> availableOperations)
    {
       playerAvailableOperations[playerId] = availableOperations;
    }
    public List<string> GetAvailableOperations(int playerId)
    {
         if (playerAvailableOperations.ContainsKey(playerId))
        {
            return playerAvailableOperations[playerId];
        }
        return new List<string>(); 

    }
    //设置弃牌
    public void SetDiscardCard(int playerId, int card)
    {
        data.UpdateDiscard(playerId, card);
    }
    //获取弃牌给manager
    public List<int> GetDiscardCardsForManager(int playerId)
    {
        data.GetDiscardCards(playerId);
    }


    // 摸牌
    public void DrawCard(int playerId)
    {
        // 获取当前摸牌索引
        int drawIndex = data.GetDrawIndex();
        // 从当前索引处获取一张牌
        int card = data.GetDrawCard()[drawIndex];
        // 更新手牌数据
        data.UpdateHandCard(playerId, card);
        // 记录最后一张摸到的牌
        data.UpdateLastDrawnCard(card);
        // 检查索引是否超出牌堆范围
        /* if (data.IsGameEndConditionMet())*/

        // 检查胡牌
        CheckHu(playerId);
        // 将索引后移一位
        data.SetDrawIndex(drawIndex + 1);
        // 判断索引是否到达牌堆末尾
        if (drawIndex + 1 >= data.GetDrawCard().Count)
        {
            // 索引到达牌堆末尾，处理牌堆耗尽的情况
            HandleDrawPileExhausted();
        }
    }
    //从data中获取最后摸到的牌
     public int DrawCardForManager(int playerId)
    {
        DrawCard(playerId);
        int card = data.GetLastDrawnCard(playerId);
        return card;
    }

    // 处理牌堆耗尽的情况
    private void HandleDrawPileExhausted()
    {
        // 在这里实现牌堆耗尽时的逻辑，例如游戏结束或重新洗牌
        Console.WriteLine("牌堆已耗尽！");
        // 可以根据游戏规则决定后续操作，例如：
        // - 结束游戏
        // - 重新洗牌并继续游戏
        // - 触发特殊游戏事件
    }


    //胡牌判断
    private void CheckHu(int playerId)
    {
        //获取对应玩家手牌进行判断
        List<int> handCards = data.GetHandCards(playerId);
        if (IsHuPossible(handCards))
        {
            //获取打出的最后一张牌作为胡牌，并且记录金牌
            int winningCard = data.GetLastDrawnCard(playerId);
            data.RecordWinningCard(playerId, winningCard);
            data.CalculateFinalScores();
            //发送游戏结束通知
            manager.GameEndHandling(data.GetFinalScores(),data.GetWinningPlayer());
        }
    }

    // 检查其他玩家响应
    public List<int> CheckOtherPlayersResponse(int playerId, int card)
    {
        // 实现检查其他玩家响应的逻辑
        //从manager中检查，通过button返回值来检查
        return new List<int>(); // 示例返回值
    }

    //获取当前游戏状态
    public GameStatus GetNextStatus()
    {
        switch (currentStatus)
        {
            case GameStatus.Preparing:
                // 准备阶段完成后进入摸牌阶段
                return GameStatus.Drawing;

            case GameStatus.Drawing:
                // 摸牌阶段完成后进入出牌阶段
                return GameStatus.Discarding;

            case GameStatus.Discarding:
                // 出牌阶段后，如果有其他玩家响应进入响应阶段，否则回到摸牌阶段
                if (CheckOtherPlayersResponse(manager.GetCurrentPlayerId(), data.GetLastDrawnCard()).Count > 0)
                {
                    return GameStatus.Responding;
                }
                else
                {
                    return GameStatus.Drawing;
                }

            case GameStatus.Responding:
                // 响应阶段完成后，根据响应结果决定下一步
                if (ResponseHandled)
                {
                    // 如果有响应处理，可能进入出牌阶段或直接结束
                    return GameStatus.Discarding;
                }
                else
                {
                    // 如果没有响应，回到摸牌阶段
                    return GameStatus.Drawing;
                }

            case GameStatus.Ended:
                // 游戏结束，保持结束状态
                return GameStatus.Ended;

            default:
                return currentStatus;
        }
    }
    //检查其他玩家可能的操作
    public List<string> CheckOtherPlayersOperations(int PlayerId, int card)
    {
        List<string> availableOperations = new List<string>();
        int playerId=manager.GetCurrentPlayerId();
        //计算下家的玩家ID
        int playerCount = data.GetPlayerCount();
        int nextPlayerId = (playerId + 1) % playerCount; 
         for (int i = 0; i < playerCount; i++)
        {
        if (i == playerId)
            continue;
        List<int> handCards = data.GetHandCards(i);
        //调用manager获取playerId
       // 检查其他玩家是否可以胡牌
            if (CanHu(i,card))
            {
                availableOperations.Add("hu");
            }
            
            // 检查其他玩家是否可以碰牌
            if (CanPeng(i,card))
            {
                availableOperations.Add("peng");
            }
            
            // 检查其他玩家是否可以杠牌
            Data.GangTypeEnum? gangType = CanGang(i, card);
            if(gangType.HasValue)
            {
                availableOperations.Add("gang");
            }
            
            // 检查下家是否可以吃牌
            List<List<int>> ChiCombinations = CanChi(i, card);
            if (nextPlayerId==i&&ChiCombinations.Count>0)
            {
                availableOperations.Add("chi");
            }
            }
            return availableOperations;
            
            }
    //获取牌的举起状态
    public void CheckPlayerRaiseStatus(int playerId)
    {
        bool isRaised = manager.GetPlayerRaiseStatus(playerId);
        if (isRaised)
        {
            /*处理举起状态的逻辑*/
        }
    }

    //判断是否可以碰牌
    public bool CanPeng(int playerId, int card)
    {
       List<int> handCards = data.GetHandCards(playerId);
        return handCards.Count(x => x == card) >= 2;
    }
    
    //判断是否可以杠牌并且返回杠牌类型
    public Data.GangTypeEnum? CanGang(int playerId, int card)
    {
        List<int> handCards = data.GetHandCards(playerId);
        List<int> pengCards = data.GetPengCards(playerId);
        List<int> discardCards = data.GetDiscardCards(playerId);

        bool canMingGang = handCards.Count(x => x == card) == 3 && discardCards.Contains(card);
        bool canAnGang = handCards.Count(x => x == card) == 4;
        bool canJiaGang = handCards.Count(x => x == card) == 1 && pengCards.Count(x => x == card) == 3;

        if (canMingGang)
        {
            return Data.GangTypeEnum.MingGang;
        }
        else if (canAnGang)
        {
            return Data.GangTypeEnum.AnGang;
        }
        else if (canJiaGang)
        {
            return Data.GangTypeEnum.JiaGang;
        }
        else
        {
            return null; // 无法杠牌
        }
    }
      
    //判断是否可以吃牌并且返回吃牌的刻子组合
    public List<List<int>> CanChi(int playerId, int card)
    {
        List<int> handCards = data.GetHandCards(playerId);
        List<List<int>> availableChiCombinations = new List<List<int>>();

        if (handCards.Contains(card - 1) && handCards.Contains(card + 1))
        {
            availableChiCombinations.Add(new List<int> { card - 1, card + 1 });
        }

        if (handCards.Contains(card - 1) && handCards.Contains(card - 2))
        {
            availableChiCombinations.Add(new List<int> { card - 2, card - 1 });
        }

        if (handCards.Contains(card + 1) && handCards.Contains(card + 2))
        {
            availableChiCombinations.Add(new List<int> { card + 1, card + 2 });
        }

        return availableChiCombinations;
    }
              
    //判断是否可以胡牌
    public bool CanHu(int playerId, int card)
    {
        List<int> handCards = data.GetHandCards(playerId);
        return IsHuPossible(handCards, card);
    }



    //碰牌
    public void PengCard(int playerId, int card)
    {
        List<int> handCards = data.GetHandCards(playerId);
        handCards.Remove(card);
        handCards.Remove(card);//移除手牌中的两张    
        manager.RemoveDiscardCard(playerId,card);//移除弃牌中的一张
        data.UpdateHandCard(playerId, handCards);//更新数据
        data.RecordPeng(playerId, card);
    }
    //杠牌（包括明杠、暗杠、加杠）
    public void GangCard(int playerId, int card, Data.GangTypeEnum gangType)
    {
        List<int> handCards = data.GetHandCards(playerId);
        List<int> pengCards = data.GetPengCards(playerId);

        switch (gangType)
        {
            case Data.GangTypeEnum.MingGang:
                handCards.RemoveAll(x => x == card);
                break;
            case Data.GangTypeEnum.AnGang:
                handCards.RemoveAll(x => x == card);
                break;
            case Data.GangTypeEnum.JiaGang:
                pengCards.RemoveAll(x => x == card);
                handCards.Remove(card);
                break;
        }

        data.RecordGang(playerId, card, gangType); // 记录杠牌
        data.UpdateHandCard(playerId, handCards); // 更新手牌数据
        data.UpdatePengCards(playerId, pengCards); // 更新碰牌区数据
    }

     //吃牌，包括吃的三种情况
    public void ChiCard(int playerId, int card, List<int> selectedPair)
    {
        List<int> handCards = data.GetHandCards(playerId);
        handCards.Remove(card);
        handCards.Remove(selectedPair[0]);
        handCards.Remove(selectedPair[1]);
        data.RecordChi(playerId, card, selectedPair); // 记录吃牌
        data.UpdateHandCard(playerId, handCards); // 更新手牌数据
    }

    public void UpdateHandCard(int playerId, List<int> handCards)
    {
        //更新Data中的手牌数据
        data.UpdateHandCard(playerId, handCards);
    }
 
    //加入金牌，生成临时List判断是否胡牌
public bool IsHuPossible(List<int> handCards, int card)
{
    int goldCard = data.GetGoldCard();
    List<int> tempHand = new List<int>(handCards);
    tempHand.Add(card); // 加上刚摸到的牌
    int goldCardCount = tempHand.Count(x => x == goldCard); // 统计手牌中已有的金牌

    // 移除所有 goldCard，准备进行替代
    tempHand.RemoveAll(x => x == goldCard);

    // 尝试将每张 goldCard 替换为不同的麻将牌
    for (int i = 0; i < goldCardCount; i++)
    {
        List<int> tempHandWithReplacement = new List<int>(tempHand);

        // 为每一张 goldCard 寻找替代牌
        for (int j = 1; j <= 31; j++) // 遍历所有可能的麻将牌
        {
            tempHandWithReplacement.Add(j); // 替换一张 goldCard 为当前牌

            if (tempHandWithReplacement.Count == 17)
            {
                if (CheckHandStructure(tempHandWithReplacement))
                {
                    return true;
                }
            }

            tempHandWithReplacement.RemoveAt(tempHandWithReplacement.Count - 1); // 移除刚刚添加的牌，准备尝试下一张
        }
    }

    // 如果没有找到合适的组合，返回 false
    return false;
}

// 检查手牌结构是否有效
private bool CheckHandStructure(List<int> handCards)
{
    if (handCards.Count != 17)
        return false;

    int[] counts = new int[32]; // 麻将牌的范围是 1-31
    foreach (int card in handCards)
    {
        counts[card]++;
    }

    return CheckStructureRecursive(counts, 0, 0);
}

// 递归检查手牌结构
private bool CheckStructureRecursive(int[] counts, int index, int tripleCount)
{
    if (index >= counts.Length)
    {
        int pairCount = 0;
        for (int i = 0; i < counts.Length; i++)
        {
            if (counts[i] == 2)
                pairCount++;
            else if (counts[i] != 0)
                return false;
        }
        return tripleCount == 5 && pairCount == 1;
    }

    // 检查是否可以形成顺子或刻子
    if (counts[index] >= 3)
    {
        counts[index] -= 3;
        tripleCount++;
        if (CheckStructureRecursive(counts, index, tripleCount))
            return true;
        counts[index] += 3;
        tripleCount--;
    }

    if (index <= 29 && counts[index] >= 1 && counts[index + 1] >= 1 && counts[index + 2] >= 1)
    {
        counts[index]--;
        counts[index + 1]--;
        counts[index + 2]--;
        tripleCount++;
        if (CheckStructureRecursive(counts, index, tripleCount))
            return true;
        counts[index]++;
        counts[index + 1]++;
        counts[index + 2]++;
        tripleCount--;
    }

    return CheckStructureRecursive(counts, index + 1, tripleCount);
}
    public int GetWinningPlayer()
    {
        return data.GetWinningPlayer();
    }
        public Dictionary<int, int> GetFinalScores()
    {
        return data.GetFinalScores();
    }
    //获取当前玩家的手牌
     public void UpdateHandCard(int playerId, int card)
    {
        data.UpdateHandCard(playerId, card);
    }

    //获取对应玩家的手牌
    public List<int> GetHandCards(int playerId)
    {
        return data.GetHandCards(playerId);
    }
    
}
}